<?php

namespace App\Http\Requests;

use App\Models\Patient;
use Illuminate\Database\Query\Builder;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class ComplaintStoreRequest extends FormRequest
{
    /**
     * @var \App\Project\FieldTranslation\FieldTranslation
     */
    protected $weight;

    /**
     * @var \App\Project\FieldTranslation\FieldTranslation
     */
    protected $dispose;

    protected $drug;

    /**
     * Determine if the user is authorized to make this request.
     * @return bool
     */
    public function authorize()
    {
        return \Auth::check();
    }

    /**
     * Prepare the data for validation.
     * @return void
     */
    protected function prepareForValidation()
    {
        $this->weight  = app('field')->get('weight');
        $this->dispose = app('field')->get('dispose');
        $this->drug    = app('field')->get('drug');
    }

    /**
     * Get the validation rules that apply to the request.
     * @return array    complaint[]['symptom']
     */
    public function rules()
    {
        return [
            'record_id'         => [
                'required', 'integer', 'min:1',
                Rule::exists('st_medical_records', 'id')->where(function (Builder $query) {
                    $query->whereNull('deleted_at');
                    $user = \Auth::user();
                    if ($user instanceof Patient) {
                        $query->where(['patient_id' => $user->id]);
                    } elseif (!$user->isDoctorsAdmin() && !$user->isAdmin()) {
                        $query->where(['doctor_id' => $user->id]);
                    }
                }),
            ],
            'symptom'           => 'array|max:5',
            'symptom.*.name'    => [
                'array', 'max:5',
                Rule::exists('tn_dic_complain', 'name')->where(function (Builder $query) {
                    $query->where(['isdel' => 0]);
                }),
            ],
            'symptoms.*.name.*' => 'string',

            'symptom.*.started_at'            => 'nullable|date',
            'symptom.*.exacerbated_at'        => 'nullable|date|after_or_equal:complaint.*.started_at',
            'blood_glucose'                   => 'nullable|array',
            'blood_glucose.limosis.low'       => 'nullable|numeric|min:0.1|max:50|decimal:1',
            'blood_glucose.limosis.high'      => 'nullable|numeric|min:0.1|max:50|decimal:1',
            'blood_glucose.postprandial.low'  => 'nullable|numeric|min:0.1|max:50|decimal:1',
            'blood_glucose.postprandial.high' => 'nullable|numeric|min:0.1|max:50|decimal:1',
            'weightchange'                    => [
                'integer',
                Rule::in(array_keys($this->weight['change'])),
            ],
            'weightchangestatus'              => [
                'required_if:weightchange,1,2',
                'import_unless_not:weightchange,0',
                Rule::in(array_keys($this->weight['status'])),
            ],
            'weightchangekg'                  => 'import_unless:weightchangestatus,1|numeric|min:0|max:999|decimal:1',

            'medication'                              => 'nullable|array',
            'medication.*.name'                       => [
                'required_with:medication.*',
                Rule::exists('st_drug_dictionary', 'name')->where(function (Builder $query) {
                    $query->whereNull('deleted_at');
                }),
            ],
            'medication.*.dosage.type'                => 'in:' . implode(',', $this->drug['dosage'][2]['type']),
            'medication.*.dosage.value'               => 'numeric|min:0|max:999|decimal:2',
            'medication.*.dosage.values'              => 'array|min:1|max:4',
            'medication.*.dosage.values.morning'      => 'numeric|decimal:2|min:0|max:999',
            'medication.*.dosage.values.atnoon'       => 'numeric|decimal:2|min:0|max:999',
            'medication.*.dosage.values.evening'      => 'numeric|decimal:2|min:0|max:999',
            'medication.*.dosage.values.before_sleep' => 'numeric|decimal:2|min:0|max:999',
            'medication.*.dosage.unit'                => 'in:' . implode(',', $this->drug['dosage'][2]['unit']),
            'medication.*.start_time'                 => 'date',
            'medication.*.end_time'                   => 'date|after_or_equal:medication.*.start_time',
            'medication.*.usage'                      => 'in:' . implode(',', $this->drug['usage'][2]),
            'medication.*.frequency'                  => 'in:' . implode(',', $this->drug['frequency'][2]),
            'medication.*.remark'                     => 'string|max:50',

            'cn_medication.*.drugs.*.name'   => [
                'string',
                Rule::exists('st_drug_dictionary', 'name')->where(function (Builder $query) {
                    $query->whereNull('deleted_at');
                }),
            ],
            'cn_medication.*.drugs.*.weight' => 'required|numeric|min:0|max:999',
            'cn_medication.*.usage'          => 'required|in:' . implode(',', $this->drug['usage'][1]),
            'cn_medication.*.dosage'         => 'required|in:' . implode(',', $this->drug['dosage'][1]['type']),
            'cn_medication.*.frequency'      => 'required|in:' . implode(',', $this->drug['frequency'][1]),
            'cn_medication.*.dose'           => 'required|integer|min:0|max:999',

            'remark' => 'nullable|string|max:255',
        ];
    }

    public function messages()
    {
        return [
            'record_id.required_without'              => '缺少病历ID',
            'record_id.integer'                       => '病历ID 必须是整数。',
            'record_id.min'                           => '病历ID 必须大于等于 :min。',
            'record_id.exists'                        => '病历 不存在或无修改该病历的权限。',
            'symptom.*.name.array'                    => '主诉症状 格式错误。',
            'symptom.*.name.max'                      => '主诉症状 最多添加 :max个。',
            'symptom.*.name.exists'                   => '主诉症状 添加了不存在的选项。',
            'symptom.*.symptom.array'                 => '主诉症状 格式错误。',
            'symptom.*.started_at.date'               => '发病时间 格式错误。',
            'symptom.*.exacerbated_at.date'           => '加重时间 格式错误。',
            'symptom.*.exacerbated_at.after'          => '加重时间 必须要晚于 发病时间。',
            'blood_glucose.limosis.low.numeric'       => '空腹血糖 必须是一个数字。',
            'blood_glucose.limosis.low.min'           => '空腹血糖 数值需要大于 :min。',
            'blood_glucose.limosis.low.max'           => '空腹血糖 数值需要小于 :max。',
            'blood_glucose.limosis.low.decimal'       => '空腹血糖 最多可保留一位小数。',
            'blood_glucose.limosis.high.numeric'      => '空腹血糖 必须是一个数字。',
            'blood_glucose.limosis.high.min'          => '空腹血糖 数值需要大于 :min。',
            'blood_glucose.limosis.high.max'          => '空腹血糖 数值需要小于 :max。',
            'blood_glucose.limosis.high.decimal'      => '空腹血糖 最多可保留一位小数。',
            'blood_glucose.postprandial.low.numeric'  => '餐后2h血糖 必须是一个数字。',
            'blood_glucose.postprandial.low.min'      => '餐后2h血糖 数值需要大于 :min。',
            'blood_glucose.postprandial.low.max'      => '餐后2h血糖 数值需要小于 :max。',
            'blood_glucose.postprandial.low.decimal'  => '餐后2h血糖 最多可保留一位小数。',
            'blood_glucose.postprandial.high.numeric' => '餐后2h血糖 必须是一个数字。',
            'blood_glucose.postprandial.high.min'     => '餐后2h血糖 数值需要大于 :min。',
            'blood_glucose.postprandial.high.max'     => '餐后2h血糖 数值需要小于 :max。',
            'blood_glucose.postprandial.high.decimal' => '餐后2h血糖 最多可保留一位小数。',

            'weightchange.integer'                 => '体重变化 必须是整数。',
            'weightchange.in'                      => '体重变化 取值错误。',
            'weightchangestatus.required_if'       => '当 体重变化 发生变化时 变化状态 不能为空。',
            'weightchangestatus.in'                => '已选的 变化状态 属性非法。',
            'weightchangestatus.import_unless_not' => '体重无变化时 变化状态不能提交。',
            'weightchangekg.import_unless'         => '体重变化明显时 才能提交变化值。',
            'weightchangekg.min'                   => '体重变化值 数值需要大于 :min。',
            'weightchangekg.max'                   => '体重变化值 数值需要小于 :max。',
            'weightchangekg.decimal'               => '体重变化值 最多可保留一位小数。',
            'remark.max'                           => '备注最大 :max 个字符',
        ];
    }
}
